<template>
  <div class="container max-w-3xl mx-auto p-4">
    <!-- 标题 -->
    <h1 class="text-2xl font-bold mb-6 text-center text-gray-800">DeepSeek 聊天助手</h1>

    <!-- 密钥配置卡片 -->
    <div class="bg-white rounded-lg shadow-md p-5 mb-6">
      <h2 class="text-xl font-semibold mb-4 text-gray-700">DeepSeek 配置</h2>

      <div class="space-y-4">
        <div class="flex items-center gap-2">
          <input
              v-model="apiConfig.apiKey"
              placeholder="API密钥"
              :type="showApiKey ? 'text' : 'password'"
              class="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
          <button
              @click="showApiKey = !showApiKey"
              class="px-3 py-2 bg-gray-200 hover:bg-gray-300 rounded-md transition-colors"
          >
            {{ showApiKey ? '隐藏' : '显示' }}
          </button>
        </div>

        <div>
          <input
              v-model="apiConfig.apiUrl"
              placeholder="API地址"
              class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
        </div>

        <div>
          <select
              v-model="apiConfig.model"
              class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          >
            <option value="deepseek-chat">deepseek-chat</option>
            <option value="deepseek-coder">deepseek-coder</option>
          </select>
        </div>

        <div class="flex gap-3">
          <button
              @click="saveApiConfig"
              class="px-4 py-2 bg-blue-600 text-white hover:bg-blue-700 rounded-md transition-colors flex-1"
          >
            保存配置
          </button>
          <button
              @click="testConnection"
              class="px-4 py-2 bg-green-600 text-white hover:bg-green-700 rounded-md transition-colors flex-1"
          >
            测试连接
          </button>
        </div>
      </div>
    </div>

    <!-- 聊天控制区 -->
    <div class="flex justify-center mb-3">
      <button
          @click="streamMode = !streamMode"
          class="px-4 py-1.5 text-sm bg-gray-200 hover:bg-gray-300 rounded-md transition-colors"
      >
        {{ streamMode ? '切换为全部打印' : '切换为流式打印' }}
      </button>
    </div>

    <!-- 聊天区域 - 增大尺寸并居中，添加唯一类名便于选择 -->
    <div class="chat-container bg-white rounded-lg shadow-md p-6 mb-6 h-[60vh] min-h-[400px] overflow-y-auto mx-auto max-w-full">
      <!-- 系统消息 -->
      <div class="text-center text-gray-500 text-sm mb-6">
        欢迎使用，可与DeepSeek对话
      </div>

      <!-- 聊天记录 -->
      <div class="space-y-6 max-w-2xl mx-auto">
        <div
            v-for="(msg, i) in messages"
            :key="i"
            class="flex"
            :class="{ 'justify-end': msg.role === 'user' }"
        >
          <div
              :class="{
              'bg-blue-100 text-blue-800': msg.role === 'user',
              'bg-gray-100 text-gray-800': msg.role !== 'user'
            }"
              class="max-w-[90%] px-5 py-3 rounded-lg shadow-sm"
          >
            <div class="font-medium text-sm mb-1.5">
              {{ msg.role === 'user' ? '我' : 'DeepSeek' }}
            </div>
            <div class="text-base leading-relaxed">
              {{ msg.content }}
            </div>
          </div>
        </div>

        <!-- 加载中 -->
        <div v-if="isLoading" class="flex justify-start">
          <div class="bg-gray-100 text-gray-800 px-5 py-3 rounded-lg shadow-sm">
            <div class="flex items-center gap-2">
              <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce"></div>
              <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style="animation-delay: 0.2s"></div>
              <div class="w-2 h-2 bg-gray-500 rounded-full animate-bounce" style="animation-delay: 0.4s"></div>
              <span>思考中...</span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 输入区域 - 增大尺寸并居中 -->
    <div class="space-y-4 max-w-2xl mx-auto w-full">
      <textarea
          v-model="inputMessage"
          placeholder="输入消息，按Enter发送"
          rows="4"
          @keyup.enter="sendMessage"
          class="w-full px-4 py-4 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 resize-none text-base"
      ></textarea>
      <button
          @click="sendMessage"
          :disabled="!inputMessage || isLoading"
          class="w-full py-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors disabled:bg-gray-400 disabled:cursor-not-allowed text-lg"
      >
        {{ isLoading ? '发送中...' : '发送消息' }}
      </button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue'

// 配置数据
const apiConfig = ref({
  apiKey: '',
  apiUrl: 'https://api.deepseek.com/v1/chat/completions',
  model: 'deepseek-chat'
})

// 聊天数据
const messages = ref([])
const inputMessage = ref('')
const isLoading = ref(false)
const showApiKey = ref(false)
const streamMode = ref(true) // 流式打印模式开关

// 页面加载时读取保存的配置
onMounted(() => {
  const savedConfig = localStorage.getItem('deepseekConfig')
  if (savedConfig) {
    try {
      apiConfig.value = JSON.parse(savedConfig)
    } catch (e) {
      console.error('加载配置失败', e)
    }
  }
})

// 保存配置到本地存储
const saveApiConfig = () => {
  if (!apiConfig.value.apiKey) {
    alert('请输入API密钥')
    return
  }

  if (!apiConfig.value.apiUrl) {
    alert('请输入API地址')
    return
  }

  localStorage.setItem('deepseekConfig', JSON.stringify(apiConfig.value))
  alert('配置已保存')
}

// 测试与API的连接
const testConnection = async () => {
  if (!apiConfig.value.apiKey) {
    alert('请填写API密钥')
    return
  }

  if (!apiConfig.value.apiUrl) {
    alert('请填写API地址')
    return
  }

  isLoading.value = true
  try {
    // 发送测试请求
    const response = await fetch(apiConfig.value.apiUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${apiConfig.value.apiKey}`
      },
      body: JSON.stringify({
        model: apiConfig.value.model,
        messages: [{ role: 'user', content: '测试连接' }],
        max_tokens: 10
      })
    })

    if (!response.ok) {
      throw new Error(`HTTP错误: ${response.status}`)
    }

    const data = await response.json()
    if (data.choices && data.choices.length > 0) {
      alert('测试成功，已收到API响应')
    } else {
      alert('测试失败，API响应格式不正确')
    }
  } catch (e) {
    console.error('连接测试失败', e)
    alert(`测试失败: ${e.message}`)
  } finally {
    isLoading.value = false
  }
}

// 发送消息到API并获取回复
const sendMessage = async () => {
  const content = inputMessage.value.trim()
  if (!content) return

  if (!apiConfig.value.apiKey) {
    alert('请先配置并保存API密钥')
    return
  }

  // 添加用户消息到聊天记录
  messages.value.push({ role: 'user', content })
  inputMessage.value = ''
  isLoading.value = true

  try {
    // 构建API请求参数
    const requestData = {
      model: apiConfig.value.model,
      messages: [
        ...messages.value.map(msg => ({
          role: msg.role,
          content: msg.content
        }))
      ],
      stream: streamMode.value // 根据模式决定是否使用流式响应
    }

    if (streamMode.value) {
      // 流式处理
      const response = await fetch(apiConfig.value.apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiConfig.value.apiKey}`
        },
        body: JSON.stringify(requestData)
      })

      if (!response.ok) {
        throw new Error(`API请求失败: ${response.status} ${response.statusText}`)
      }

      // 创建一个临时消息用于逐字显示
      const tempMessageId = messages.value.length
      messages.value.push({ role: 'assistant', content: '' })

      // 处理流式响应
      const reader = response.body.getReader()
      const decoder = new TextDecoder()

      while (true) {
        const { done, value } = await reader.read()
        if (done) break

        const chunk = decoder.decode(value, { stream: true })
        const lines = chunk.split('\n').filter(line => line.trim() !== '')

        for (const line of lines) {
          const data = line.replace('data: ', '')
          if (data === '[DONE]') break

          try {
            const json = JSON.parse(data)
            if (json.choices && json.choices[0]?.delta?.content) {
              // 逐字添加内容
              messages.value[tempMessageId].content += json.choices[0].delta.content
              // 确保滚动到底部
              await nextTick()
              scrollToBottom()
            }
          } catch (e) {
            console.error('解析流式响应失败', e)
          }
        }
      }
    } else {
      // 非流式处理（全部打印）
      const response = await fetch(apiConfig.value.apiUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${apiConfig.value.apiKey}`
        },
        body: JSON.stringify(requestData)
      })

      if (!response.ok) {
        throw new Error(`API请求失败: ${response.status} ${response.statusText}`)
      }

      const data = await response.json()

      // 处理API响应
      if (data.choices && data.choices.length > 0) {
        const aiResponse = data.choices[0].message
        messages.value.push(aiResponse)
        scrollToBottom()
      } else {
        throw new Error('未收到有效的回复内容')
      }
    }
  } catch (e) {
    console.error('发送消息失败', e)
    alert(`发送失败: ${e.message}`)
    // 移除刚才添加的用户消息，保持一致性
    messages.value.pop()
  } finally {
    isLoading.value = false
  }
}

// 滚动到聊天底部 - 修复选择器错误
const scrollToBottom = () => {
  // 使用专用类名选择器，避免特殊字符问题
  const chatContainer = document.querySelector('.chat-container')
  if (chatContainer) {
    chatContainer.scrollTop = chatContainer.scrollHeight
  }
}
</script>

<style>
/* 基础样式 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

body {
  background-color: #f5f7fa;
  color: #333;
}

/* 动画效果 */
@keyframes bounce {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(-5px);
  }
}

.animate-bounce {
  animation: bounce 1s infinite;
}
</style>
